Merge nmi_op functionality with the callback_op hypercall.
authorIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Fri, 21 Apr 2006 16:19:22 +0000 (17:19 +0100)
committerIan.Campbell@xensource.com <Ian.Campbell@xensource.com>
Fri, 21 Apr 2006 16:19:22 +0000 (17:19 +0100)
Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
linux-2.6-xen-sparse/include/asm-i386/mach-xen/setup_arch_post.h
linux-2.6-xen-sparse/include/asm-x86_64/mach-xen/setup_arch_post.h
xen/arch/x86/x86_32/traps.c
xen/arch/x86/x86_64/traps.c
xen/common/kernel.c
xen/include/public/callback.h
xen/include/xen/nmi.h

index 5107aacd4d70f9fb7fb9b04158ed97e1455fad74..a349bb18a0ddae14aecc96805ab0ab3be183d7af 100644 (file)
@@ -34,7 +34,10 @@ static void __init machine_specific_arch_setup(void)
                .type = CALLBACKTYPE_failsafe,
                .address = { __KERNEL_CS, (unsigned long)failsafe_callback },
        };
-       struct xennmi_callback cb;
+       struct callback_register nmi_cb = {
+               .type = CALLBACKTYPE_nmi,
+               .address = { __KERNEL_CS, (unsigned long)nmi },
+       };
 
        if (xen_feature(XENFEAT_auto_translated_physmap) &&
            xen_start_info->shared_info < xen_start_info->nr_pages) {
@@ -52,8 +55,14 @@ static void __init machine_specific_arch_setup(void)
                        failsafe.address.cs, failsafe.address.eip);
        BUG_ON(ret);
 
-       cb.handler_address = (unsigned long)&nmi;
-       HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
+       ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
+       if (ret == -ENOSYS) {
+               struct xennmi_callback cb;
+
+               cb.handler_address = nmi_cb.address.eip;
+               ret = HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
+       }
+       BUG_ON(ret);
 
        if (HYPERVISOR_xen_version(XENVER_platform_parameters,
                                   &pp) == 0)
index 725ea90c0358a973395977ceb055bfe30c2d4978..aca5ba7e658ecc1a8a9998a80aa9ada4672056f0 100644 (file)
@@ -28,7 +28,10 @@ static void __init machine_specific_arch_setup(void)
                .address = (unsigned long)system_call,
        };
 #ifdef CONFIG_X86_LOCAL_APIC
-       struct xennmi_callback cb;
+       struct callback_register nmi_cb = {
+               .type = CALLBACKTYPE_nmi,
+               .address = (unsigned long)nmi,
+       };
 #endif
 
        ret = HYPERVISOR_callback_op(CALLBACKOP_register, &event);
@@ -44,7 +47,13 @@ static void __init machine_specific_arch_setup(void)
        BUG_ON(ret);
 
 #ifdef CONFIG_X86_LOCAL_APIC
-       cb.handler_address = (unsigned long)&nmi;
-       HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
+       ret = HYPERVISOR_callback_op(CALLBACKOP_register, &nmi_cb);
+       if (ret == -ENOSYS) {
+               struct xennmi_callback cb;
+
+               cb.handler_address = nmi_cb.address;
+               ret = HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
+       }
+       BUG_ON(ret);
 #endif
 }
index 085c1261531ccf9cc937f7303b4e6557c0940832..dfba38c56666a7e6804746eb3b972fbc124a2f3c 100644 (file)
@@ -10,6 +10,7 @@
 #include <xen/irq.h>
 #include <xen/symbols.h>
 #include <xen/reboot.h>
+#include <xen/nmi.h>
 #include <asm/current.h>
 #include <asm/flushtlb.h>
 #include <asm/hvm/hvm.h>
@@ -336,6 +337,10 @@ static long register_guest_callback(struct callback_register *reg)
         v->arch.guest_context.failsafe_callback_eip = reg->address.eip;
         break;
 
+    case CALLBACKTYPE_nmi:
+        ret = register_guest_nmi_callback(reg->address.eip);
+        break;
+
     default:
         ret = -EINVAL;
         break;
@@ -350,6 +355,10 @@ static long unregister_guest_callback(struct callback_unregister *unreg)
 
     switch ( unreg->type )
     {
+    case CALLBACKTYPE_nmi:
+        ret = unregister_guest_nmi_callback();
+        break;
+
     default:
         ret = -EINVAL;
         break;
index 4f5ff5ba112ea6a673516fb660d65d76af9aac1d..62ac6fa1b5c29b6a6dc4f1a504c641ef469c11f3 100644 (file)
@@ -11,6 +11,7 @@
 #include <xen/console.h>
 #include <xen/sched.h>
 #include <xen/reboot.h>
+#include <xen/nmi.h>
 #include <asm/current.h>
 #include <asm/flushtlb.h>
 #include <asm/msr.h>
@@ -339,6 +340,10 @@ static long register_guest_callback(struct callback_register *reg)
         v->arch.guest_context.syscall_callback_eip  = reg->address;
         break;
 
+    case CALLBACKTYPE_nmi:
+        ret = register_guest_nmi_callback(reg->address);
+        break;
+
     default:
         ret = -EINVAL;
         break;
@@ -353,6 +358,10 @@ static long unregister_guest_callback(struct callback_unregister *unreg)
 
     switch ( unreg->type )
     {
+    case CALLBACKTYPE_nmi:
+        ret = unregister_guest_nmi_callback();
+        break;
+
     default:
         ret = -EINVAL;
         break;
index a2a23fb70f602ea61d3fbf2fbf105de9f31b535a..f7dffadd69290d4e84a1d5aa6ebbe16350d6442c 100644 (file)
@@ -213,37 +213,51 @@ long do_xen_version(int cmd, GUEST_HANDLE(void) arg)
     return -ENOSYS;
 }
 
-long do_nmi_op(unsigned int cmd, GUEST_HANDLE(void) arg)
+long register_guest_nmi_callback(unsigned long address)
 {
     struct vcpu *v = current;
     struct domain *d = current->domain;
+
+    if ( (d->domain_id != 0) || (v->vcpu_id != 0) )
+        return -EINVAL;
+
+    v->nmi_addr = address;
+#ifdef CONFIG_X86
+    /*
+     * If no handler was registered we can 'lose the NMI edge'. Re-assert it
+     * now.
+     */
+    if ( d->shared_info->arch.nmi_reason != 0 )
+        set_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
+#endif
+
+    return 0;
+}
+
+long unregister_guest_nmi_callback(void)
+{
+    struct vcpu *v = current;
+
+    v->nmi_addr = 0;
+
+    return 0;
+}
+
+long do_nmi_op(unsigned int cmd, GUEST_HANDLE(void) arg)
+{
     struct xennmi_callback cb;
     long rc = 0;
 
     switch ( cmd )
     {
     case XENNMI_register_callback:
-        rc = -EINVAL;
-        if ( (d->domain_id != 0) || (v->vcpu_id != 0) )
-            break;
-
         rc = -EFAULT;
         if ( copy_from_guest(&cb, arg, 1) )
             break;
-
-        v->nmi_addr = cb.handler_address;
-#ifdef CONFIG_X86
-        /*
-         * If no handler was registered we can 'lose the NMI edge'. Re-assert 
-         * it now.
-         */
-        if ( d->shared_info->arch.nmi_reason != 0 )
-            set_bit(_VCPUF_nmi_pending, &v->vcpu_flags);
-#endif
-        rc = 0;
+        rc = register_guest_nmi_callback(cb.handler_address);
         break;
     case XENNMI_unregister_callback:
-        v->nmi_addr = 0;
+        rc = unregister_guest_nmi_callback();
         break;
     default:
         rc = -ENOSYS;
index 479333ddb8e5ef7865cf92656ab2436faa08a687..27877c72ad40e841a9a7dbc9f44cb2657116731f 100644 (file)
@@ -21,6 +21,7 @@
 #define CALLBACKTYPE_event                 0
 #define CALLBACKTYPE_failsafe              1
 #define CALLBACKTYPE_syscall               2 /* x86_64 only */
+#define CALLBACKTYPE_nmi                   4
 
 /*
  * Register a callback.
index e526b6ab6f41694740bd0f9f4efb8ff1aebfee8a..a13e797273b22dd0ad86c48d8ab60797da91a499 100644 (file)
 
 #include <asm/nmi.h>
 
+/**
+ * register_guest_nmi_callback
+ *
+ * The default NMI handler passes the NMI to a guest callback. This
+ * function registers the address of that callback.
+ */
+extern long register_guest_nmi_callback(unsigned long address);
+
+/**
+ * unregister_guest_nmi_callback
+ *
+ * Unregister a guest NMI handler.
+ */
+extern long unregister_guest_nmi_callback(void);
+
 #endif /* __XEN_NMI_H__ */